package com.zsr.example.config.filter;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.zsr.example.config.annotation.BusinessLog;
import com.zsr.example.entity.SysLog;
import com.zsr.example.service.SysLogService;
import com.zsr.example.util.IPUtil;
import com.zsr.example.util.JwtUtil;
import com.zsr.example.util.RequestUtil;
import com.zsr.example.util.constants.ErrorEnum;
import com.zsr.example.util.constants.SysLogConstants;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.MDC;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.util.Date;
import java.util.Map;

/**
 * @author zsr
 * @description: 打印每个请求的入参、出参等信息
 */
@Aspect
@Component
@Slf4j
@Order(1)
public class WebLogAspect {

    @Autowired
    private SysLogService sysLogService;


    @Pointcut("execution(public * com.zsr.example.controller..*.*(..))")
    public void webLog() {
    }

    @Pointcut("@annotation(com.zsr.example.config.annotation.BusinessLog)")
    //@annotation声明以注解的方式来定义切点
    public void businessLog() {
    }

    @Pointcut(" execution(public * com.zsr.example.config.exception.GlobalExceptionHandler.*(..))")
    public void exceptions() {
    }

    /**
     * 只在进入controller时记录请求信息
     */
    @Before("webLog()")
    public void doBefore(JoinPoint joinPoint) {
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();
        log.debug("IP {}  请求路径 {} ,进入方法 {}", IPUtil.getIpAddress(request), request.getRequestURI(), joinPoint.getSignature().getDeclaringTypeName() + ":" + joinPoint.getSignature().getName());
        MDC.put("req", RequestUtil.getRequestInfo(request).toJSONString());
        MDC.put("startTime", String.valueOf(System.currentTimeMillis()));
    }

    /**
     * 打印请求日志
     */
    @AfterReturning(pointcut = "businessLog()|| exceptions()", returning = "result")
//returning能够将目标方法的返回值传到切面增强方法里
    public void afterReturning(JoinPoint joinPoint, Object result) {
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();

        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        BusinessLog annotation = signature.getMethod().getAnnotation(BusinessLog.class);

        Map<String, String> map = MDC.getCopyOfContextMap();
        if (map != null) {

            long startTime = System.currentTimeMillis() - Long.parseLong(map.getOrDefault("startTime", String.valueOf(System.currentTimeMillis())));
            String requestURI = request.getRequestURI();
            String userId = map.getOrDefault("userId", "");
            JSONObject req = JSON.parseObject(map.getOrDefault("req", ""));
            SysLog sysLog = new SysLog().setUserId(userId).setUri(requestURI).setTook(startTime);
            if (req != null) {
                sysLog.setMethod(req.getString(SysLogConstants.METHOD))
                        .setRequestUrl(req.getString(SysLogConstants.REQUEST_URL))
                        .setQueryString(req.getString(SysLogConstants.QUERY_STRING))
                        .setRemoteAddr(req.getString(SysLogConstants.REMOTE_ADDR))
                        .setRequestBody(req.getString(SysLogConstants.REQUEST_BODY));
                if (userId.isEmpty()) {
                    sysLog.setUserId(JwtUtil.getMemberIdByJwtToken(request));
                }
            }
            boolean isSave = true;
            if (result != null) {
                //jsonObject.put("res", res);
                JSONObject res = JSON.parseObject(result.toString());
                sysLog.setResult(result.toString());
                if (res.getString("code").equals(ErrorEnum.E_400.getErrorCode())) {//出现了代码错误
                    sysLog.setLevel(SysLogConstants.LEVEL_ERROR);
                    sysLog.setCreateTime(new Date());
                    //sysLog.setDescription(ErrorEnum.E_400.getErrorMsg());
                } else {
                    if (annotation != null && annotation.isSaveResult()) {
                        //使用注解记录日志为debug
                        sysLog.setLevel(SysLogConstants.LEVEL_INFO);
                        sysLog.setDescription(annotation.description());
                    } else {
                        //自定义异常为warn 暂不存数据库
                        sysLog.setLevel(SysLogConstants.LEVEL_WARN);
                        //sysLog.setDescription(res.getString("msg"));
                        isSave = false;
                    }
                }

            }

            if (isSave) sysLogService.save(sysLog);
            //log.info(jsonObject.toJSONString());
        }
    }


}
